package com.hzw.saas.api.storage;

import com.hzw.saas.api.storage.bo.ResourceFileBO;
import com.hzw.saas.api.storage.bo.ResourceFileStorageBO;
import com.hzw.saas.api.storage.query.ResourceFileUpdateQuery;
import com.hzw.saas.common.config.query.LogicQuery;
import com.hzw.saas.common.util.enums.AssertEnum;
import com.hzw.saas.common.util.enums.ConflictModeEnum;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

/**
 * <p>
 * 资源文件服务接口
 * </p>
 *
 * @author zzl
 * @since 2020-12-24
 */
public interface IResourceFileService {

    /**
     * 获取正常状态的文件信息
     *
     * @param pid        文件ID
     * @param assertEnum 结果检查, null或IGNORE-跳过结果检查
     * @return 文件信息
     */
    ResourceFileBO getFile(String pid, AssertEnum assertEnum);

    /**
     * 获取文件信息
     *
     * @param pid        文件ID
     * @param status     资源状态, 可为null
     * @param integrity  文件完整性状态，null-不过滤
     * @param assertEnum 结果检查, null或IGNORE-跳过结果检查
     * @return 文件信息
     */
    ResourceFileBO getFile(String pid, LogicQuery<Integer> status, LogicQuery<Integer> integrity, AssertEnum assertEnum);

    /**
     * 获取指定Id的正常状态文件列表
     *
     * @param pidList 文件ID列表
     * @return 满足条件的文件列表
     */
    List<ResourceFileBO> listFiles(List<String> pidList);

    /**
     * 获取指定Id的文件列表
     *
     * @param pidList   文件ID列表
     * @param status    资源状态, 可为null
     * @param integrity 文件完整性状态，null-不过滤
     * @return 文件列表
     */
    List<ResourceFileBO> listFiles(List<String> pidList, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 获取指定目录下正常状态的文件
     *
     * @param supId 父目录ID
     * @return 文件信息列表
     */
    List<ResourceFileBO> listSubFiles(String supId);

    /**
     * 获取指定目录下的文件
     *
     * @param supId     父目录ID
     * @param status    文件状态，可选
     * @param integrity 文件完整性状态，可选
     * @return 文件信息列表
     */
    List<ResourceFileBO> listSubFiles(String supId, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 获取指定目录下正常状态的文件
     *
     * @param supIdList 父目录ID列表
     * @return 文件信息列表
     */
    List<ResourceFileBO> listSubFiles(List<String> supIdList);

    /**
     * 获取指定目录下的文件
     *
     * @param supIdList 父目录ID
     * @param status    文件状态，可选
     * @param integrity 文件完整性状态，可选
     * @return 文件信息列表
     */
    List<ResourceFileBO> listSubFiles(List<String> supIdList, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 获取用户正常状态的所有文件
     *
     * @param userId  用户ID
     * @param spaceId 存储空间ID
     * @return 文件信息列表
     */
    List<ResourceFileBO> listUserFiles(String userId, String spaceId);

    /**
     * 获取用户指定状态的所有文件
     *
     * @param userId    用户ID
     * @param spaceId   存储空间ID
     * @param status    文件状态，可选
     * @param integrity 文件完整性状态，可选
     * @return 文件信息列表
     */
    List<ResourceFileBO> listUserFiles(String userId, String spaceId, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 获取目录中文件ID列表
     *
     * @param supId     父目录ID
     * @param status    资源状态, 可为null
     * @param integrity 文件完整性状态，可为null
     * @return 子文件PID列表
     */
    List<String> listSubFilePids(String supId, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 获取目录中文件ID列表
     *
     * @param supIds    父目录ID
     * @param status    资源状态, 可为null
     * @param integrity 文件完整性状态，可为null
     * @return 子文件PID列表
     */
    List<String> listSubFilePids(List<String> supIds, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 获取文件信息，含存储信息
     *
     * @param pid        文件ID
     * @param status     资源状态, 可为null
     * @param integrity  文件完整性状态，null-不过滤
     * @param assertEnum 结果检查, null或IGNORE-跳过结果检查
     * @return 文件信息
     */
    ResourceFileStorageBO getFileWithStorage(String pid, LogicQuery<Integer> status, LogicQuery<Integer> integrity, AssertEnum assertEnum);

    /**
     * 获取stats=200的最新文件
     *
     * @param vid       版本号ID
     * @param status    文件状态，null-忽略
     * @param integrity 文件完整性，null-忽略
     * @return 最新版本文件
     */
    ResourceFileBO getLatestFile(String vid, LogicQuery<Integer> status, LogicQuery<Integer> integrity, AssertEnum assertEnum);

    /**
     * 检查目录下文件名是否存在
     *
     * @param supId    父目录ID
     * @param fileName 文件名
     * @param status   资源状态, 可为null
     * @return true 存在, false 不存在
     */
    boolean isNameExist(String supId, String fileName, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 获取用户指定状态的所有文件的数量
     *
     * @param userId    用户ID
     * @param spaceIds  存储空间ID
     * @param status    资源状态, 可为null
     * @param integrity 文件完整性状态，null-不过滤
     * @return 文件数量
     */
    int countNumberByUser(String userId, List<String> spaceIds, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 统计目录下文件数量
     *
     * @param supId     父目录ID
     * @param status    文件状态
     * @param integrity 文件完整性
     * @return 文件数量
     */
    int countNumberBySup(String supId, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 统计文件列表的大小
     *
     * @param pidList 文件ID列表
     * @return 大小，单位：byte
     */
    long countSizeByPid(List<String> pidList, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 获取用户指定状态的所有文件的大小
     *
     * @param userId    用户ID
     * @param spaceIds  存储空间ID列表
     * @param status    资源状态, 可为null
     * @param integrity 文件完整性状态，null-不过滤
     * @return 文件大小，单位：byte
     */
    long countSizeByUser(String userId, List<String> spaceIds, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 统计目录下文件大小
     *
     * @param supId     父目录ID
     * @param status    文件状态，可选
     * @param integrity 文件完整性，可选
     * @return 大小，单位：byte
     */
    long countSizeBySupId(String supId, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * @param supIdList
     * @param status
     * @param integrity
     * @return
     */
    long countSizeBySupId(List<String> supIdList, LogicQuery<Integer> status, LogicQuery<Integer> integrity);

    /**
     * 检查资是否属于用户
     *
     * @param userId 用户ID
     * @param fileId 文件ID
     * @return 结果 true/false
     */
    boolean checkAuthOwn(String userId, String fileId);

    /**
     * @param userId
     * @param fileId
     */
    void assertAuthOwn(String userId, String fileId);

    /**
     * 检查资是否属于用户
     *
     * @param userId     用户ID
     * @param fileIdList 文件ID列表
     */
    boolean checkAuthOwn(String userId, List<String> fileIdList);

    /**
     * 检查资是否属于用户
     * 如果有不属于用户的文件则抛出异常
     *
     * @param userId     用户ID
     * @param fileIdList 文件ID列表
     */
    void assertAuthOwn(String userId, List<String> fileIdList);

    /**
     * 新建文件信息
     *
     * @param fileBo         文件信息, supId, name, catalog不可为空
     * @param conflictHandle 冲突解决方案
     * @return 文件信息，含生成的文件ID
     */
    ResourceFileStorageBO saveFile(ResourceFileStorageBO fileBo, ConflictModeEnum conflictHandle);

    /**
     * 新建文件信息，保存文件
     *
     * @param fileBo           文件信息, supId, name, catalog不可为空
     * @param inputStream      文件流
     * @param conflictModeEnum 冲突解决方案
     * @return 文件信息，含生成的文件ID
     */
    ResourceFileStorageBO saveFile(ResourceFileStorageBO fileBo, InputStream inputStream, ConflictModeEnum conflictModeEnum);

    /**
     * 新建文件信息，保存文件
     *
     * @param fileBo           文件信息, supId, name, catalog不可为空
     * @param file             文件
     * @param conflictModeEnum 冲突解决方案
     * @return 文件信息，含生成的文件ID
     */
    ResourceFileStorageBO saveFile(ResourceFileStorageBO fileBo, MultipartFile file, ConflictModeEnum conflictModeEnum);

    /**
     * 复制文件
     *
     * @param srcPid         原文件ID
     * @param tarSupId       目标父目录ID
     * @param newName        新文件名，为空则使用原文件名
     * @param conflictHandle 文件名冲突解决方案
     */
    void copyFile(String srcPid, String tarSupId, String newName, ConflictModeEnum conflictHandle);

    /**
     * 复制文件信息
     *
     * @param srcPidList     原文件ID列表
     * @param tarSupId       目标父目录ID
     * @param conflictHandle 文件名冲突解决方案
     */
    void copyFiles(List<String> srcPidList, String tarSupId, ConflictModeEnum conflictHandle);

    /**
     * 复制原目录中的所有子文件到指定目录
     *
     * @param srcSupId       原父目录ID，必要
     * @param tarSupId       指定父目录ID，必要
     * @param conflictHandle 文件名冲突处理
     */
    void copySubFiles(String srcSupId, String tarSupId, ConflictModeEnum conflictHandle);

    /**
     * 移动文件
     *
     * @param pid            文件ID
     * @param tarSupId       目标父目录ID
     * @param newName        新文件名，为空则使用原文件名
     * @param conflictHandle 文件名冲突解决方案
     */
    void moveFile(String pid, String tarSupId, String newName, ConflictModeEnum conflictHandle);

    /**
     * 移动文件
     *
     * @param pidList        原文件ID列表
     * @param tarSupId       目标父目录ID
     * @param conflictHandle 文件名冲突解决方案
     */
    void moveFiles(List<String> pidList, String tarSupId, ConflictModeEnum conflictHandle);

    /**
     * 移动原目录中的所有子文件到指定目录
     *
     * @param srcSupId       原父目录ID，必要
     * @param tarSupId       指定父目录ID，必要
     * @param conflictHandle 文件名冲突处理
     */
    void moveSubFiles(String srcSupId, String tarSupId, ConflictModeEnum conflictHandle);

    /**
     * 重命名文件
     *
     * @param pid            文件ID
     * @param newName        新名称
     * @param conflictHandle 文件名冲突解决方案
     */
    void renameFile(String pid, String newName, ConflictModeEnum conflictHandle);

    /**
     * 回收文件
     *
     * @param pid 文件ID
     */
    void recycleFile(String pid);

    /**
     * 批量回收文件
     *
     * @param pidList 文件ID
     */
    void recycleFiles(List<String> pidList);

    /**
     * 回收目录中的子文件
     * 为目录回收时，同时回收子文件使用
     *
     * @param supId 父目录ID
     */
    void recycleSubFiles(String supId);

    /**
     * 恢复文件
     *
     * @param pid      文件ID
     * @param tarSupId 恢复至的父目录ID，可选。为空时，恢复至文件原父目录
     */
    void restoreFile(String pid, String tarSupId, String newName, ConflictModeEnum conflictHandle);

    /**
     * 批量恢复文件
     *
     * @param pidList  文件ID列表
     * @param tarSupId 恢复至的父目录ID，可选。为空时，恢复至文件原父目录
     */
    void restoreFiles(List<String> pidList, String tarSupId, ConflictModeEnum conflictHandle);

    /**
     * 恢复目录中的子文件
     * 一般为恢复目录时同时恢复子文件操作
     *
     * @param srcSupId 父目录ID
     * @param tarSupId 恢复至的父目录ID，可选。为空时，恢复至文件原父目录
     */
    void restoreSubFiles(String srcSupId, String tarSupId, ConflictModeEnum conflictHandle);

    /**
     * 删除文件
     *
     * @param pid 文件ID
     */
    void deleteFile(String pid);

    /**
     * 批量删除文件
     *
     * @param pidList 文件ID
     */
    void deleteFiles(List<String> pidList);

    /**
     * 删除目录中的子文件
     * 为目录删除时，同时删除子文件使用
     *
     * @param supId 父目录ID
     */
    void deleteSubFiles(String supId);

    /**
     * 复活文件
     * 将已被删除的文件复活
     * 一般在文件版本中使用，复活低版本文件
     *
     * @param pid      文件ID
     * @param tarSupId 恢复至的父目录ID，可选。为空时，恢复至文件原父目录
     */
    void resurrectFile(String pid, String tarSupId, String newName, ConflictModeEnum conflictHandle);

    /**
     * 批量复活文件
     * 将已被删除的文件复活
     * 一般在文件版本中使用，复活低版本文件
     *
     * @param pidList  文件ID列表
     * @param tarSupId 恢复至的父目录ID，可选。为空时，恢复至文件原父目录
     */
    void resurrectFiles(List<String> pidList, String tarSupId, ConflictModeEnum conflictHandle);

    /**
     * 更新文件信息
     *
     * @param file2Update 文件信息
     */
    boolean updateFile(ResourceFileUpdateQuery file2Update);

    boolean updateFileByResourceKey(String resourceKey, ResourceFileUpdateQuery file2Update);

    /**
     * 更新文件完整性状态
     *
     * @param pid       文件ID
     * @param integrity 文件完整性
     */
    boolean updateFileIntegrity(String pid, Integer integrity);

    /**
     * 下载文件
     *
     * @param pid        文件ID
     * @param ous        文件流
     * @param startBytes 起始字节，如501，即为从501字节处开始下载
     */
    void downloadFileData(String pid, OutputStream ous, long startBytes);

    /**
     * 获取文件对象，若不在本地，会从S3上拉取到本地
     *
     * @param pid        文件ID
     * @param assertEnum 存在性断言
     * @return 文件对象
     */
    File getFileData(String pid, AssertEnum assertEnum);

    /**
     * 文件存储管理
     *
     * @param pid         文件ID
     * @param storageMode 存储模式
     * @param async       true-异步处理，false-同步处理
     */
    void dealStorageMode(String pid, Integer storageMode, boolean async);

}
